home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Human Interface Toolbox / ZoomWindow / DoBetterWZoom.c
Encoding:
Text File  |  2000-09-28  |  5.9 KB  |  148 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        DoBetterWZoom.c
  3.  
  4.     Contains:    The new functionality is really cool. I now pass in maximum bounds for the window and 
  5.                 make all sorts of adjustments to ensure that the window is zoomed to a good size at a 
  6.                     good place while minimizing unnecessary window motion. This implementation is slightly 
  7.                 better than the one used by the Finder in View by Icon.
  8.  
  9.     Written by:     
  10.  
  11.     Copyright:    Copyright © 1984-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.                 You may incorporate this Apple sample source code into your program(s) without
  14.                 restriction. This Apple sample source code has been provided "AS IS" and the
  15.                 responsibility for its operation is yours. You are not permitted to redistribute
  16.                 this Apple sample source code as "Apple sample source code" after having made
  17.                 changes. If you're going to re-distribute the source, we require that you make
  18.                 it clear in the source that the code was descended from Apple sample source
  19.                 code, but that you've made changes.
  20.  
  21.     Change History (most recent first):
  22.                 8/6/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  23.                 
  24.  
  25. */
  26. void DoZoomWindow (WindowPtr theWindow, short zoomDir, short hMax, short vMax)
  27. {
  28.     extern EventRecord    gTheEvent;                        // from the main event loop
  29.     extern Boolean        gHasColorQD;
  30.  
  31.     Rect                *windRect, *zoomRect;
  32.     Rect                globalPortRect, theSect, dGDRect;
  33.     GDHandle            nthDevice, dominantGDevice;
  34.     long                sectArea, greatestArea;
  35.  
  36.     if (TrackBox(theWindow, gTheEvent.where, zoomDir)) {
  37.         SetPort(theWindow);
  38.         EraseRect(&theWindow->portRect);    // recommended for cosmetic reasons
  39.  
  40.         if (zoomDir == inZoomOut) {
  41.  
  42.             /*
  43.              *    ZoomWindow() is a good basic tool, but it doesn't do everything necessary to
  44.              *    implement a good human interface when zooming. In fact it's not even close for
  45.              *    more high-end hardware configurations. We must help it along by calculating an
  46.              *    appropriate window size and location any time a window zooms out.
  47.              */
  48.  
  49.             windRect = &(**((WindowPeek) theWindow)->strucRgn).rgnBBox;
  50.             dominantGDevice = nil;
  51.             if (gHasColorQD) {
  52.  
  53.                 /*
  54.                  *    Color QuickDraw implies the possibility of multiple monitors. This is where
  55.                  *    zooming becomes more interesting. One should zoom onto the monitor containing
  56.                  *    the greatest portion of the window. This requires walking the gDevice list.
  57.                  */
  58.  
  59.                 nthDevice = GetDeviceList();
  60.                 greatestArea = 0;
  61.                 while (nthDevice != nil) {
  62.                     if (TestDeviceAttribute(nthDevice, screenDevice)) {
  63.                         if (TestDeviceAttribute(nthDevice, screenActive)) {
  64.                             SectRect(windRect, &(**nthDevice).gdRect, &theSect);
  65.                             sectArea = (long) rectWidth(theSect) * (long) rectHeight(theSect);
  66.                             if (sectArea > greatestArea) {
  67.                                 greatestArea = sectArea;        // save the greatest intersection
  68.                                 dominantGDevice = nthDevice;    // and which device it belongs to
  69.                             }
  70.                         }
  71.                     }
  72.                     nthDevice = GetNextDevice(nthDevice);
  73.                 }
  74.             }
  75.  
  76.             /*
  77.              *    At this point, we know the dimensions of the window we're zooming, and we know
  78.              *    what screen we're going to put it on. To be more specific, however, we need a
  79.              *    rectangle which defines the maximum dimensions of the resized window's contents.
  80.              *    This rectangle accounts for the thickness of the window frame, the menu bar, and
  81.              *    one or two pixels around the edges for cosmetic compatibility with ZoomWindow().
  82.              */
  83.  
  84.             if (dominantGDevice != nil) {
  85.                 dGDRect = (**dominantGDevice).gdRect;
  86.                 if (dominantGDevice == GetMainDevice())        // account for menu bar on main device
  87.                     dGDRect.top += GetMBarHeight();
  88.             }
  89.             else {
  90.                 dGDRect = qd.screenBits.bounds;                // if no gDevice, use default monitor
  91.                 dGDRect.top += GetMBarHeight();
  92.             }
  93.  
  94.             globalPortRect = theWindow->portRect;
  95.             LocalToGlobal(&topLeft(globalPortRect));        // calculate the window's portRect
  96.             LocalToGlobal(&botRight(globalPortRect));        // in global coordinates
  97.  
  98.             // account for the window frame and inset it a few pixels
  99.             dGDRect.left    += 2 + globalPortRect.left - windRect->left;
  100.             dGDRect.top        += 2 + globalPortRect.top - windRect->top;
  101.             dGDRect.right    -= 1 + windRect->right - globalPortRect.right;
  102.             dGDRect.bottom    -= 1 + windRect->bottom - globalPortRect.bottom;
  103.  
  104.             /*
  105.              *    Now we know exactly what our limits are, and since there are input parameters
  106.              *    specifying the dimensions we'd like to see, we can move and resize the zoom
  107.              *    state rectangle for the best possible results. We have three goals in this:
  108.              *    1. Display the window entirely visible on a single device.
  109.              *    2. Resize the window to best represent the dimensions of the document itself.
  110.              *    3. Move the window as short a distance as possible to achieve #1 and #2.
  111.              */
  112.  
  113.             zoomRect = &(**(WStateDataHandle) ((WindowPeek) theWindow)->dataHandle).stdState;
  114.  
  115.             /*
  116.              *    Initially set the zoom rectangle to the size requested by the input parameters,
  117.              *    although not smaller than a minimum size. We do this without moving the origin.
  118.              */
  119.  
  120.             zoomRect->right = (zoomRect->left = globalPortRect.left) +
  121.                                     max(hMax, MinWindowWidth(theWindow));
  122.             zoomRect->bottom = (zoomRect->top = globalPortRect.top) +
  123.                                     max(vMax, MinWindowHeight(theWindow));
  124.  
  125.             // Shift the entire rectangle if necessary to bring its origin inside dGDRect.
  126.             OffsetRect(zoomRect,
  127.                         max(dGDRect.left - zoomRect->left, 0),
  128.                         max(dGDRect.top - zoomRect->top, 0));
  129.  
  130.             /*
  131.              *    Shift the rectangle up and/or to the left if necessary to accomodate the view,
  132.              *    and if it is possible to do so. The rectangle may not be moved such that its
  133.              *    origin would fall outside of dGDRect.
  134.              */
  135.  
  136.             OffsetRect(zoomRect,
  137.                         -pin(zoomRect->right - dGDRect.right, 0, zoomRect->left - dGDRect.left),
  138.                         -pin(zoomRect->bottom - dGDRect.bottom, 0, zoomRect->top - dGDRect.top));
  139.  
  140.             // Clip expansion to dGDRect, in case view is larger than dGDRect.
  141.             zoomRect->right = min(zoomRect->right, dGDRect.right);
  142.             zoomRect->bottom = min(zoomRect->bottom, dGDRect.bottom);
  143.         }
  144.  
  145.         ZoomWindow(theWindow, zoomDir, false);        // all it needed was a brain transplant
  146.     }
  147. }
  148.